/*
 * WaveImpl.h
 *
 *  Created on: 2011/05/28
 *      Author: naoki
 */

#ifndef INCLUDED_NTENGINE_SOUND_WAVEIMPL_H
#define INCLUDED_NTENGINE_SOUND_WAVEIMPL_H

#include "NTEngine/NTEngine.h"
#include "NTEngine/Sound/Wave.h"
#include "NTEngine/FileIO/InFile.h"
#include "NTEngine/Base/ReferenceCounter.h"
#include "NTEngine/Base/RefString.h"

#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>

namespace NTEngine {
namespace Sound {

class Wave::Impl : public ReferenceCounter {
public:
	Impl( const char* filename )
	: mBuffer( 0 )
	, mSize( 0 )
	, mFile()
	, mIsError( false )	{
		setupInitFormat();
		mFile = FileIO::InFile::create( filename );
	}

	Impl( const unsigned char* buffer, unsigned size )
	: mBuffer( 0 )
	, mSize( 0 )
	, mFile()
	, mIsError( false ) {
		setupInitFormat();
		mSize = size;
		mBuffer = NEW unsigned char[ mSize ];
		memcpy( mBuffer, buffer, mSize );
	}

	~Impl() {
		SAFE_DELETE_ARRAY( mBuffer );
		mSize = 0;
	}

	bool isReady() {
		if ( mFile ) {
			if ( mFile.isFinished() ) {
				if ( mFile.isError() ) {
					mIsError = true;
				} else {
					RefString waveStr( "WAVE" );
					if ( waveStr == RefString( mFile.data() + 8, 4 ) ) {
						// Waveファイル
						int channels = mFile.getShort( 22 );
						int frequency = mFile.getInt( 24 );
						int bitsPerSample = mFile.getShort( 34 );
						const char* data = mFile.data();
						int waveSize = 0;
						int waveStart = 0;
						int pos = 36;
						// リニアPCMのみ対応。拡張ヘッダは無視する
						RefString dataStr( "data" );
						while ( dataStr != RefString( data + pos, 4 ) ){ //いらないものが入っている間飛ばす
							if ( pos >= mFile.size() ){
								mIsError = true;
								break;
							}
							pos += mFile.getInt( pos+4 ); //いらないもののサイズがここに入っている
						}
						if ( channels > 1 ) {
							mIsError = true; // 2ch以上は対応していない。残念
						}
						if ( !mIsError ){
							waveSize = mFile.getInt( pos + 4 );
							waveStart = pos + 8;
							//データサイズがファイルサイズより小さい事が良くある。エラーにはしない。
							if ( waveSize + waveStart > mFile.size() ){
								waveSize = mFile.size() - waveStart;
							}
							mFormat.numChannels = channels;
							mFormat.samplesPerSec = frequency * 1000; // kHzなので1000倍してHzに直す
							mFormat.bitsPerSample = bitsPerSample;
							mFormat.containerSize = bitsPerSample;
							mSize = waveSize;
							mBuffer = NEW unsigned char[ mSize ];
							memcpy( mBuffer, mFile.data() + waveStart, mSize );
						}
					} else {
						HALT( no implement );
					}
					mFile.release();
				}
				return true;
			} else {
				return false;
			}
		}
		return true;
	}

	void setupInitFormat() {
		mFormat.formatType = SL_DATAFORMAT_PCM;
		mFormat.channelMask = SL_SPEAKER_FRONT_CENTER;
		mFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;
	}

	unsigned char* mBuffer;
	unsigned mSize;

	// ファイル関連
	FileIO::InFile mFile;
	bool mIsError;
	SLDataFormat_PCM mFormat;
};

} // namespace Sound
} // namespace NTEngine

#endif // INCLUDED_NTENGINE_SOUND_WAVEIMPL_H
